/*
 * shinglehashtable.h
 *
 *  Created on: Jun 6, 2011
 *      Author: timothy
 */

#ifndef HASHTABLE_H
#define HASHTABLE_H

#include <omp.h>
#include <map>

#include "shingletypes.h"
#include "init.h"

class ShingleHashtable;
class ShingleHashtableEntry;

class ShingleHashtable
{
	private:
		ShingleHashtableEntry **table;
		ShingleHashtableEntry **mostRecentEntries;
		ShingleHashtableEntry **iterators;
		ShingleHashtableEntry **firstEntry;

		omp_lock_t *write_locks;
		int count;

		ShingleHashtableEntry **tableBackup;


		ShingleHashtableEntry *check(long unsigned int key, int nthShingle);
		long unsigned int indexOf(long unsigned int key);
		unsigned long int getKey(Shingle *s);
		void lock(unsigned long index);
		void unlock(unsigned long index);
	public:
		// FIELDS //
		unsigned long Size;
		omp_lock_t table_lock;
		double chkTimes[MAX_THREADS_DEBUG];
		double genTimes[MAX_THREADS_DEBUG];
		double insTimes[MAX_THREADS_DEBUG];
		double lstTimes[MAX_THREADS_DEBUG];

		double lockingTimes[MAX_THREADS_DEBUG];
		double lockedTimes[MAX_THREADS_DEBUG];
		double lastLock[MAX_THREADS_DEBUG];
		int collisions[MAX_THREADS_DEBUG];
		int timesLocked[MAX_THREADS_DEBUG];

		// CONSTRUCTORS //
		ShingleHashtable(int vertices);
		~ShingleHashtable();

		// METHODS //
		// Adds the shingle GENERATED BY item to the hashtable
		// In the case of duplicate shingles, this will merely add extra links to the existing one.
		// In the case of an actual collision, this will use ShingleHashtableEntry->Next
		// This method is OMP critical
		void Insert(Vertex *item, int nthShingle);
		void Insert(Shingle *item, int nthShingle);
		void InnerInsert(Shingle *ins);

		// Finds a shingle in the hashtable
		// This method is threadsafe
		// Returns NULL if no value exists at the given key.
		Shingle *Fetch(unsigned long key, int nthShingle);

		// Gets the current number of items
		int Count();

		// Functions for iterating through the hashtable.
		void InitIterator();
		Shingle *Iterate();
		void checkTable();
};

class ShingleHashtableEntry
{
	private:
		ShingleHashtableEntry *Next;
		int hasMemoryBlock;
		int neighborCount;
		ShingleHashtableEntry *parent;

	public:
	// FIELDS //
	Shingle *Item;
	int Finished;

	// Next via collision resolution
	// Next via iteration
	ShingleHashtableEntry *ListNext;

	// CONSTRUCTORS //
	ShingleHashtableEntry(Shingle *item);
	~ShingleHashtableEntry();


	static ShingleHashtableEntry *AllocateShingleHashtableEntry(Shingle *item);
	static void Deallocate();
	void ClearData();
	static void SetupAllocs();

	void SetNext(ShingleHashtableEntry *to);
	ShingleHashtableEntry *GetNext();
};

#endif
